<?php

declare(strict_types=1);

namespace App\Middleware;

use GuzzleHttp\Middleware;
use GuzzleHttp\RetryMiddleware;
use Psr\Http\Message\RequestInterface;
use Psr\Http\Message\ResponseInterface;
use Throwable;

class GuzzleRetryMiddleware
{
    public static function create(int $maxRetries = 2): callable
    {
        return Middleware::retry(
            function (
                $retries,
                RequestInterface $request,
                ResponseInterface $response = null,
                Throwable $exception = null
            ) use ($maxRetries) {
                // 最大重试次数检查
                if ($retries >= $maxRetries) {
                    return false;
                }

                // 如果有异常，检查是否需要重试
                if ($exception !== null) {
                    return self::isRetryableException($exception);
                }

                // 如果有响应，检查状态码
                if ($response !== null) {
                    return $response->getStatusCode() >= 500;
                }

                return false;
            },
            function ($retries) {
                return 1000 * pow(2, $retries);
            }
        );
    }

    private static function isRetryableException(Throwable $exception): bool
    {
        $message = $exception->getMessage();

        $retryableMessages = [
            'Empty reply from server',
            'cURL error 52',
            'cURL error 6',
            'cURL error 7',
            'cURL error 28',
            'cURL error 35',
            'Connection refused',
            'Connection timed out',
            'Operation timed out',
        ];

        foreach ($retryableMessages as $pattern) {
            if (strpos($message, $pattern) !== false) {
                return true;
            }
        }

        // 检查异常类型
        $retryableClasses = [
            \GuzzleHttp\Exception\ConnectException::class,
            \GuzzleHttp\Exception\RequestException::class,
        ];

        foreach ($retryableClasses as $class) {
            if ($exception instanceof $class) {
                return true;
            }
        }

        return false;
    }
}